#include "test.h"

void test_all(void) {

    int result;
    const char* result_string[] = { "Error", "Right" };

    printf("Start testing each module for correctness...\n");
    printf("Module\t\tResult\n");
    // test fp
    result = 1;
    result &= test_fp_add();
    result &= test_fp_sub();
    result &= test_fp_neg();
    result &= test_fp_haf();
    result &= test_fp_dou();
    result &= test_fp_inv();
    result &= test_fp_mul();
    printf("FP\t\t%s\n", result_string[result]);

    // test fn
    result = 1;
    result &= test_fn_add();
    result &= test_fn_sub();
    result &= test_fn_inv();
    result &= test_fn_mul();
    printf("FN\t\t%s\n", result_string[result]);

    // test point
    result = 1;
    result &= test_point_add();
    result &= test_point_add_affine_jacobian();
    result &= test_point_dou();
    result &= test_point_mdo();
    result &= test_point_mul();
    result &= test_point_mul_fixed();
    printf("POINT\t\t%s\n", result_string[result]);

    // test sm2
    result = 1;
    result &= test_sm2_enc();
    result &= test_sm2_dec();
    result &= test_sm2_sign();
    result &= test_sm2_verify();
    printf("SM2\t\t%s\n", result_string[result]);


    // test sm3
    result = 1;
    result &= test_sm3();
    printf("SM3\t\t%s\n", result_string[result]);

    // test sm4
    result = 1;
    result &= test_sm4_enc();
    result &= test_sm4_dec();
    printf("SM4\t\t%s\n", result_string[result]);
    printf("The test is over.\n\n");

}

int test_fp_add(void) {
    fp x, y, t, r;
    fp_fm_str(x, "E7BA3D4240D179AA38C580FFF968EE2EDB4A8EF6CF64E30A4B770A0CC69020ED");
    fp_fm_str(y, "9DDD52AF95B748A553D1B1E106627F901CD453F067A0D50202C672130C90F607");
    fp_fm_str(r, "85978FF2D688C24F8C9732E0FFCB6DBEF81EE2E83705B80B4E3D7C1FD32116F5");
    fp_add(t, x, y);
    return fp_equ(t, r);
}

int test_fp_sub(void) {
    fp x, y, t, r;
    fp_fm_str(x, "E7BA3D4240D179AA38C580FFF968EE2EDB4A8EF6CF64E30A4B770A0CC69020ED");
    fp_fm_str(y, "FDDD52AF95B748A553D1B1E106627F901CD453F067A0D50202C672130C90F607");
    fp_fm_str(r, "E9DCEA91AB1A3104E4F3CF1EF3066E9EBE763B0567C40E0948B097F9B9FF2AE5");
    fp_sub(t, x, y);
    return fp_equ(t, r);
}

int test_fp_neg(void) {
    fp x, t, r;
    fp_fm_str(x, "E7BA3D4240D179AA38C580FFF968EE2EDB4A8EF6CF64E30A4B770A0CC69020ED");
    fp_fm_str(r, "1845C2BCBF2E8655C73A7F00069711D124B57108309B1CF6B488F5F3396FDF12");
    fp_neg(t, x);
    return fp_equ(t, r);
}

int test_fp_dou(void) {
    fp x, t, r;
    fp_fm_str(x, "E7BA3D4240D179AA38C580FFF968EE2EDB4A8EF6CF64E30A4B770A0CC69020ED");
    fp_fm_str(r, "CF747A8581A2F354718B01FFF2D1DC5DB6951DEE9EC9C61396EE14198D2041DB");
    fp_dou(t, x);
    return fp_equ(t, r);
}

int test_fp_haf(void) {
    fp x, t, r;
    fp_fm_str(x, "E7BA3D4240D179AA38C580FFF968EE2EDB4A8EF6CF64E30A4B770A0CC69020ED");
    fp_fm_str(r, "F3DD1EA0A068BCD51C62C07FFCB477176DA5477AE7B27185A5BB850663481076");
    fp_haf(t, x);
    return fp_equ(t, r);
}

int test_fp_inv(void) {
    fp x, t, r;
    fp_fm_str(x, "E7BA3D4240D179AA38C580FFF968EE2EDB4A8EF6CF64E30A4B770A0CC69020ED");
    fp_fm_str(r, "28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93");
    fp_inv(t, x);
    return fp_equ(t, r);
}

int test_fp_mul(void) {
    fp x, y, t, r;
    fp_fm_str(x, "E7BA3D4240D179AA38C580FFF968EE2EDB4A8EF6CF64E30A4B770A0CC69020ED");
    fp_fm_str(y, "9DDD52AF95B748A553D1B1E106627F901CD453F067A0D50202C672130C90F607");
    fp_fm_str(r, "4084F63BFFAE5AA8701C27E1F3C197299E064097A4B6D1A5A28E90872A095614");
    fp_mul(t, x, y);
    return fp_equ(t, r);
}

int test_fn_add(void) {
    fp x, y, t, r;
    fp_fm_str(x, "E7BA3D4240D179AA38C580FFF968EE2EDB4A8EF6CF64E30A4B770A0CC69020ED");
    fp_fm_str(y, "9DDD52AF95B748A553D1B1E106627F901CD453F067A0D50202C672130C90F607");
    fp_fm_str(r, "85978FF2D688C24F8C9732E0FFCB6DBF861B037C153FB2E0FA818816994BD5D1");
    fn_add(t, x, y);
    return fp_equ(t, r);
}

int test_fn_sub(void) {
    fp x, y, t, r;
    fp_fm_str(x, "E7BA3D4240D179AA38C580FFF968EE2EDB4A8EF6CF64E30A4B770A0CC69020ED");
    fp_fm_str(y, "FDDD52AF95B748A553D1B1E106627F901CD453F067A0D50202C672130C90F607");
    fp_fm_str(r, "E9DCEA91AB1A3104E4F3CF1EF3066E9E307A1A71898A13339C6C8C02F3D46C09");
    fn_sub(t, x, y);
    return fp_equ(t, r);
}

int test_fn_inv(void) {
    fp x, t, r;
    fp_fm_str(x, "E7BA3D4240D179AA38C580FFF968EE2EDB4A8EF6CF64E30A4B770A0CC69020ED");
    fp_fm_str(r, "4E40BE003921C68372FFB6B2F75C5CC22E007A35FFF138434643A4524A727272");
    fn_inv(t, x);
    return fp_equ(t, r);
}

int test_fn_mul(void) {
    fp x, y, t, r;
    fp_fm_str(x, "E7BA3D4240D179AA38C580FFF968EE2EDB4A8EF6CF64E30A4B770A0CC69020ED");
    fp_fm_str(y, "9DDD52AF95B748A553D1B1E106627F901CD453F067A0D50202C672130C90F607");
    fp_fm_str(r, "E2B6D58F9FC8CC4011850CD77E173F39E929392ED09404A67B842F4ADF2C02C9");
    fn_mul(t, x, y);
    return fp_equ(t, r);
}

int test_point_add(void) {
    point p, q, r, t;
    jpoint jp, jq, jt;
    fp_fm_str(p.x, "E7BA3D4240D179AA38C580FFF968EE2EDB4A8EF6CF64E30A4B770A0CC69020ED");
    fp_fm_str(p.y, "9DDD52AF95B748A553D1B1E106627F901CD453F067A0D50202C672130C90F607");
    fp_fm_str(q.x, "421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D");
    fp_fm_str(q.y, "0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2");
    fp_fm_str(r.x, "68A499B8B89806D30852AF8D85D07FF70A30F93B1A416AC6A1C411E1E7D261F1");
    fp_fm_str(r.y, "7EB38011FC432E66F5E6166CB9E461008A2CD82B5A14B4AFDB25DEC8B7622B4B");
    jpoint_set(&jp, p.x, p.y, one);
    jpoint_set(&jq, q.x, q.y, one);
    jpoint_add(&jt, &jp, &jq);
    point_fm_jpoint(&t, &jt);
    return fp_equ(t.x, r.x) & fp_equ(t.y, r.y);
}

int test_point_add_affine_jacobian(void) {
    point q, r, t;
    jpoint jp, jt;
    fp_fm_str(jp.x, "E7BA3D4240D179AA38C580FFF968EE2EDB4A8EF6CF64E30A4B770A0CC69020ED");
    fp_fm_str(jp.y, "9DDD52AF95B748A553D1B1E106627F901CD453F067A0D50202C672130C90F607");
    fp_fm_str(jp.z, "0000000000000000000000000000000000000000000000000000000000000001");
    fp_fm_str(q.x, "421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D");
    fp_fm_str(q.y, "0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2");
    fp_fm_str(r.x, "68A499B8B89806D30852AF8D85D07FF70A30F93B1A416AC6A1C411E1E7D261F1");
    fp_fm_str(r.y, "7EB38011FC432E66F5E6166CB9E461008A2CD82B5A14B4AFDB25DEC8B7622B4B");
    jpoint_add_AJ(&jt, &jp, &q);
    point_fm_jpoint(&t, &jt);
    return fp_equ(t.x, r.x) & fp_equ(t.y, r.y);
}

int test_point_dou(void) {
    point p, r, t;
    jpoint jp, jt;
    fp_fm_str(p.x, "421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D");
    fp_fm_str(p.y, "0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2");
    fp_fm_str(r.x, "61C36A2DEF5DC5E56C4F9A77B16FC92AEC342D5EAE52521F716A38D3A46C84D3");
    fp_fm_str(r.y, "A16FB5481138B6BDF81164EB5CC1721EA755DA1A240F9D19E941E2166516AD16");
    jpoint_set(&jp, p.x, p.y, one);
    jpoint_dou(&jt, &jp);
    point_fm_jpoint(&t, &jt);
    return fp_equ(t.x, r.x) & fp_equ(t.y, r.y);
}

int test_point_mdo(void) {
    point p, r, t;
    jpoint jp, jt;
    u32 m = 6;
    fp_fm_str(p.x, "421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D");
    fp_fm_str(p.y, "0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2");
    fp_fm_str(r.x, "A2BCEBCC908C39CC2091090F0375D1271968790DC2914F348EE76CFC6E3AF8C1");
    fp_fm_str(r.y, "65F2C7D3A7D1D516E60B476A71C0E62BA62F0939CC6BA0134358E54BB57FFD93");
    jpoint_set(&jp, p.x, p.y, one);
    jpoint_mdo(&jt, m, &jp);
    point_fm_jpoint(&t, &jt);
    return fp_equ(t.x, r.x) & fp_equ(t.y, r.y);
}

int test_point_mul(void) {
    fp k;
    point p, r, t;
    jpoint jp, jt;
    fp_fm_str(k, "3945208F7B2144B13F36E38AC6D39F95889393692860B51A42FB81EF4DF7C5B8");
    fp_fm_str(p.x, "04EBFC718E8D1798620432268E77FEB6415E2EDE0E073C0F4F640ECD2E149A73");
    fp_fm_str(p.y, "E858F9D81E5430A57B36DAAB8F950A3C64E6EE6A63094D99283AFF767E124DF0");
    fp_fm_str(r.x, "335E18D751E51F040E27D468138B7AB1DC86AD7F981D7D416222FD6AB3ED230D");
    fp_fm_str(r.y, "AB743EBCFB22D64F7B6AB791F70658F25B48FA93E54064FDBFBED3F0BD847AC9");
    jpoint_set(&jp, p.x, p.y, one);
    jpoint_mul(&jt, k, &jp);
    point_fm_jpoint(&t, &jt);
    return fp_equ(t.x, r.x) & fp_equ(t.y, r.y);
}

int test_point_mul_fixed(void) {
    fp k;
    point r, t;
    jpoint jt;
    fp_fm_str(k, "3945208F7B2144B13F36E38AC6D39F95889393692860B51A42FB81EF4DF7C5B8");
    fp_fm_str(r.x, "09F9DF311E5421A150DD7D161E4BC5C672179FAD1833FC076BB08FF356F35020");
    fp_fm_str(r.y, "CCEA490CE26775A52DC6EA718CC1AA600AED05FBF35E084A6632F6072DA9AD13");
    jpoint_mul_fixed(&jt, k);
    point_fm_jpoint(&t, &jt);
    return fp_equ(t.x, r.x) & fp_equ(t.y, r.y);
}

int test_sm3(void) {
    // Test Example 1 of GB/T 32905-2016
    u8 message1[] = "abc";
    u8 digest1[32];
    u8 rdigest1[32] = {0x66, 0xC7, 0xF0, 0xF4, 0x62, 0xEE, 0xED, 0xD9, 0xD1, 0xF2, 0xD4, 0x6B, 0xDC, 0x10, 0xE4, 0xE2,
                       0x41, 0x67, 0xC4, 0x87, 0x5c, 0xf2, 0xf7, 0xa2, 0x29, 0x7d, 0xa0, 0x2b, 0x8f, 0x4b, 0xa8, 0xe0};
    sm3(digest1, message1, (sizeof(message1) - 1) << 3);

    // Test Example 2 of GB/T 32905-2016
    u8 digest2[32];
    u8 message2[] = "abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd";
    u8 rdigest2[32] = {0xDE, 0xBE, 0x9F, 0xF9, 0x22, 0x75, 0xB8, 0xA1, 0x38, 0x60, 0x48, 0x89, 0xC1, 0x8E, 0x5A, 0x4D,
                       0x6F, 0xDB, 0x70, 0xE5, 0x38, 0x7E, 0x57, 0x65, 0x29, 0x3D, 0xCB, 0xA3, 0x9C, 0x0C, 0x57, 0x32};
    sm3(digest2, message2, (sizeof(message2) - 1) << 3);

    return memcmp(digest1, rdigest1, 32) == 0 && memcmp(digest2, rdigest2, 32) == 0;
}

int test_sm2_sign(void) {

    char msq[] = "message digest";
    char id[] = "1234567812345678";
    sm2_private_key prikey;
    sm2_signature signature;

    byt_fm_str(prikey.prikey,   "3945208F7B2144B13F36E38AC6D39F95889393692860B51A42FB81EF4DF7C5B8");
    byt_fm_str(prikey.pubkey.x, "09F9DF311E5421A150DD7D161E4BC5C672179FAD1833FC076BB08FF356F35020");
    byt_fm_str(prikey.pubkey.y, "CCEA490CE26775A52DC6EA718CC1AA600AED05FBF35E084A6632F6072DA9AD13");


    u8 dgst[32], buf[72];

    u8 result[72] = {0x30, 0x46, 0x02, 0x21, 0x00, 0xf5, 0xa0, 0x3b, 0x06, 0x48, 0xd2, 0xc4, 0x63, 0x0e, 0xea, 0xc5, 0x13, 0xe1,
                     0xbb, 0x81, 0xa1, 0x59, 0x44, 0xda, 0x38, 0x27, 0xd5, 0xb7, 0x41, 0x43, 0xac, 0x7e, 0xac, 0xee, 0xe7, 0x20,
                     0xb3, 0x02, 0x21, 0x00, 0xb1, 0xb6, 0xaa, 0x29, 0xdf, 0x21, 0x2f, 0xd8, 0x76, 0x31, 0x82, 0xbc, 0x0d, 0x42,
                     0x1c, 0xa1, 0xbb, 0x90, 0x38, 0xfd, 0x1f, 0x7f, 0x42, 0xd4, 0x84, 0x0b, 0x69, 0xc4, 0x85, 0xbb, 0xc1, 0xaa};


    sm2_sign_init(dgst, &prikey.pubkey, id, strlen(id), (u8*) msq, strlen(msq));
    sm2_sign(&signature, &prikey, dgst);

    u64 blen = 0;
    u8 *_buf = buf;
    sm2_sig_to_der(signature, &_buf, &blen);

    return memcmp(buf, result, sizeof(result)) == 0;
}

int test_sm2_verify(void) {
    char msq[] = "message digest";
    char id[] = "1234567812345678";
    sm2_public_key pubkey;
    sm2_signature signature;
    u8 dgst[32];
    u8 sig_der[] = {0x30, 0x46, 0x02, 0x21, 0x00, 0xf5, 0xa0, 0x3b, 0x06, 0x48, 0xd2, 0xc4, 0x63, 0x0e, 0xea, 0xc5,
                    0x13, 0xe1,
                    0xbb, 0x81, 0xa1, 0x59, 0x44, 0xda, 0x38, 0x27, 0xd5, 0xb7, 0x41, 0x43, 0xac, 0x7e, 0xac, 0xee,
                    0xe7, 0x20,
                    0xb3, 0x02, 0x21, 0x00, 0xb1, 0xb6, 0xaa, 0x29, 0xdf, 0x21, 0x2f, 0xd8, 0x76, 0x31, 0x82, 0xbc,
                    0x0d, 0x42,
                    0x1c, 0xa1, 0xbb, 0x90, 0x38, 0xfd, 0x1f, 0x7f, 0x42, 0xd4, 0x84, 0x0b, 0x69, 0xc4, 0x85, 0xbb,
                    0xc1, 0xaa};
    const u8 *_sig_der = sig_der;
    u64 sig_len = sizeof(sig_der);
    byt_fm_str(pubkey.x, "09F9DF311E5421A150DD7D161E4BC5C672179FAD1833FC076BB08FF356F35020");
    byt_fm_str(pubkey.y, "CCEA490CE26775A52DC6EA718CC1AA600AED05FBF35E084A6632F6072DA9AD13");
    sm2_sig_from_der(&signature, &_sig_der, &sig_len);
    sm2_verify_init(dgst, &pubkey, id, strlen(id), (u8*) msq, strlen(msq));
    return sm2_verify(&signature, &pubkey, dgst);
}

int test_sm2_enc(void) {
    char msq[] = "encryption standard";
    sm2_public_key pubkey;
    sm2_ciptext ctext = {0};
    u8 result[126] = {0x30, 0x7c, 0x02, 0x20, 0x04, 0xeb, 0xfc, 0x71, 0x8e, 0x8d, 0x17, 0x98, 0x62, 0x04, 0x32, 0x26,
                      0x8e, 0x77,
                      0xfe, 0xb6, 0x41, 0x5e, 0x2e, 0xde, 0x0e, 0x07, 0x3c, 0x0f, 0x4f, 0x64, 0x0e, 0xcd, 0x2e, 0x14,
                      0x9a, 0x73,
                      0x02, 0x21, 0x00, 0xe8, 0x58, 0xf9, 0xd8, 0x1e, 0x54, 0x30, 0xa5, 0x7b, 0x36, 0xda, 0xab, 0x8f,
                      0x95, 0x0a,
                      0x3c, 0x64, 0xe6, 0xee, 0x6a, 0x63, 0x09, 0x4d, 0x99, 0x28, 0x3a, 0xff, 0x76, 0x7e, 0x12, 0x4d,
                      0xf0, 0x04,
                      0x20, 0x59, 0x98, 0x3c, 0x18, 0xf8, 0x09, 0xe2, 0x62, 0x92, 0x3c, 0x53, 0xae, 0xc2, 0x95, 0xd3,
                      0x03, 0x83,
                      0xb5, 0x4e, 0x39, 0xd6, 0x09, 0xd1, 0x60, 0xaf, 0xcb, 0x19, 0x08, 0xd0, 0xbd, 0x87, 0x66, 0x04,
                      0x13, 0x21,
                      0x88, 0x6c, 0xa9, 0x89, 0xca, 0x9c, 0x7d, 0x58, 0x08, 0x73, 0x07, 0xca, 0x93, 0x09, 0x2d, 0x65,
                      0x1e, 0xfa};
    u64 len = 0;
    u8 buf[300], *_buf = buf;
    u8 ciphertext[sizeof(msq)] = {0};
    ctext.ctext = ciphertext;

    byt_fm_str(pubkey.x, "09F9DF311E5421A150DD7D161E4BC5C672179FAD1833FC076BB08FF356F35020");
    byt_fm_str(pubkey.y, "CCEA490CE26775A52DC6EA718CC1AA600AED05FBF35E084A6632F6072DA9AD13");

    sm2_encrypt(&ctext, &pubkey, msq);
    sm2_ciptext_to_der(ctext, &_buf, &len);

    return memcmp(buf, result, sizeof(result)) == 0;
}

int test_sm2_dec(void) {
    char msq[] = "encryption standard";
    sm2_private_key prikey;
    sm2_ciptext ct = {0};
    u8 ct_der[] = {0x30, 0x7c, 0x02, 0x20, 0x04, 0xeb, 0xfc, 0x71, 0x8e, 0x8d, 0x17, 0x98, 0x62, 0x04, 0x32, 0x26, 0x8e,
                   0x77,
                   0xfe, 0xb6, 0x41, 0x5e, 0x2e, 0xde, 0x0e, 0x07, 0x3c, 0x0f, 0x4f, 0x64, 0x0e, 0xcd, 0x2e, 0x14, 0x9a,
                   0x73,
                   0x02, 0x21, 0x00, 0xe8, 0x58, 0xf9, 0xd8, 0x1e, 0x54, 0x30, 0xa5, 0x7b, 0x36, 0xda, 0xab, 0x8f, 0x95,
                   0x0a,
                   0x3c, 0x64, 0xe6, 0xee, 0x6a, 0x63, 0x09, 0x4d, 0x99, 0x28, 0x3a, 0xff, 0x76, 0x7e, 0x12, 0x4d, 0xf0,
                   0x04,
                   0x20, 0x59, 0x98, 0x3c, 0x18, 0xf8, 0x09, 0xe2, 0x62, 0x92, 0x3c, 0x53, 0xae, 0xc2, 0x95, 0xd3, 0x03,
                   0x83,
                   0xb5, 0x4e, 0x39, 0xd6, 0x09, 0xd1, 0x60, 0xaf, 0xcb, 0x19, 0x08, 0xd0, 0xbd, 0x87, 0x66, 0x04, 0x13,
                   0x21,
                   0x88, 0x6c, 0xa9, 0x89, 0xca, 0x9c, 0x7d, 0x58, 0x08, 0x73, 0x07, 0xca, 0x93, 0x09, 0x2d, 0x65, 0x1e,
                   0xfa};
    u8 pt[sizeof(msq) - 1];
    const u8 *_ct_der = ct_der;
    u64 l = sizeof(ct_der);
    u8 ciphertext[sizeof(ct_der)];
    ct.ctext = ciphertext;
    sm2_ciptext_from_der(&ct, &_ct_der, &l);

    byt_fm_str(prikey.prikey,   "3945208F7B2144B13F36E38AC6D39F95889393692860B51A42FB81EF4DF7C5B8");
    byt_fm_str(prikey.pubkey.x, "09F9DF311E5421A150DD7D161E4BC5C672179FAD1833FC076BB08FF356F35020");
    byt_fm_str(prikey.pubkey.y, "CCEA490CE26775A52DC6EA718CC1AA600AED05FBF35E084A6632F6072DA9AD13");

    sm2_decrypt(pt, &prikey, &ct);

    return memcmp(pt, msq, sizeof(msq) - 1) == 0;
}

int test_sm4_enc(void) {

    // Test Example 1 of GB/T 32907-2016
    u8 pt1[16] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10};
    u8 kt1[16] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10};
    u8 ct1[16] = {0x68, 0x1e, 0xdf, 0x34, 0xd2, 0x06, 0x96, 0x5e, 0x86, 0xb3, 0xe9, 0x4f, 0x53, 0x6e, 0x42, 0x46};
    u8 rt1[16] = {0};
    sm4_encrypt(rt1, pt1, kt1);

    // Test Example 2 of GB/T 32907-2016
    u8 pt2[16] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10};
    u8 kt2[16] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10};
    u8 ct2[16] = {0x59, 0x52, 0x98, 0xC7, 0xC6, 0xFD, 0x27, 0x1F, 0x04, 0x02, 0xF8, 0x04, 0xC3, 0x3D, 0x3F, 0x66};
    for (int i = 1000000; i > 0; i--)
        sm4_encrypt(pt2, pt2, kt2);

    return memcmp(rt1, ct1, 16) == 0 && memcmp(pt2, ct2, 16) == 0;
}

int test_sm4_dec(void) {

    // Test Example 1 of GB/T 32907-2016
    u8 ct1[16] = {0x68, 0x1e, 0xdf, 0x34, 0xd2, 0x06, 0x96, 0x5e, 0x86, 0xb3, 0xe9, 0x4f, 0x53, 0x6e, 0x42, 0x46};
    u8 kt1[16] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10};
    u8 pt1[16] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10};
    u8 rt1[16] = {0};
    sm4_decrypt(rt1, ct1, kt1);

    // Test Example 2 of GB/T 32907-2016
    u8 ct2[16] = {0x59, 0x52, 0x98, 0xC7, 0xC6, 0xFD, 0x27, 0x1F, 0x04, 0x02, 0xF8, 0x04, 0xC3, 0x3D, 0x3F, 0x66};
    u8 kt2[16] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10};
    u8 pt2[16] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10};

    for (int i = 1000000; i > 0; i--)
        sm4_decrypt(ct2, ct2, kt2);

    return memcmp(rt1, pt1, 16) == 0 && memcmp(ct2, pt2, 16) == 0;
}